using System;
using System.Net.Sockets;
using System.Text;

public enum UserStatus
{
	Online,
	DoNotDisturb,
	Offline
}

//====================================================================
//			RemoteUser ----- has a -----> UserConnection.
//====================================================================

public class RemoteUser : IDisposable
{


	//====================================================================

	public event ReceivedTextEventHandler ReceivedText;
	public delegate void ReceivedTextEventHandler(RemoteUser Sender, string Message);
	public event ConnectedEventHandler Connected;
	public delegate void ConnectedEventHandler(RemoteUser Sender);
	public event DisconnectedEventHandler Disconnected;
	public delegate void DisconnectedEventHandler(RemoteUser Sender);
	public event StatusChangedEventHandler StatusChanged;
	public delegate void StatusChangedEventHandler(RemoteUser Sender);

	//====================================================================

	#region " Constructors and destructors "

	public RemoteUser(string Addr)
	{
		Address = Addr;
		Name = Addr;
	}

	public RemoteUser(string UserName, string Addr)
	{
		Address = Addr;
		Name = UserName;
	}

	//====================================================================

	~RemoteUser()
	{
		Dispose();
	}

	public void Dispose()
	{
		Disconnect();
	}

	#endregion

	#region " Connect / Disconnect "

	//====================================================================

	public void ConnectInitiate(string LocalUserName, string LocalUserAddress)
	{
		if (IsOnline()) return; // TODO: might not be correct. Was : Exit Sub
 

		TcpClient NewClient;

		try {
			NewClient = new TcpClient(this.Address, modMain.PortNum);
			Connection = new UserConnection(NewClient);

			SendMessage(MessageType.Connect, LocalUserName + "|" + LocalUserAddress);
			Status = UserStatus.Online;
			if (Connected != null) {
				Connected(this);
			}
		}

		catch (Exception e) {
			Disconnect();
		}
	}

	//====================================================================

	public void ConnectRespond(UserConnection ExistingConnection)
	{
		Connection = ExistingConnection;
		Status = UserStatus.Online;
		if (Connected != null) {
			Connected(this);
		}
	}

	//====================================================================

	private void mConnection_Terminated(UserConnection Sender)
	{
		Disconnect();
		if (Disconnected != null) {
			Disconnected(this);
		}
	}

	public void Disconnect()
	{
		//Implements IRemoteUser.Disconnect
		if ((Connection != null))
		{
			Connection.Dispose();
			Connection = null;
		}
		Status = UserStatus.Offline;
	}

	#endregion

	//====================================================================

	private UserConnection mConnection;
	protected UserConnection Connection {
		get { return mConnection; }
		set
		{
			if (mConnection != null)
			{
				mConnection.Terminated -= mConnection_Terminated;
				mConnection.LineReceived -= mConnection_LineReceived;
			}
			mConnection = value;
			if (mConnection != null)
			{
				mConnection.Terminated += mConnection_Terminated;
				mConnection.LineReceived += mConnection_LineReceived;
			}
		}
	}

	//====================================================================

	#region " Sending data "

	public void SendText(string Message)
	{
		if (IsOnline())
		{
			SendMessage(MessageType.Chat, Message);
		}
	}

	public void SendStatus(UserStatus NewStatus)
	{
		string StatusString = "";
		switch (NewStatus) {
			case UserStatus.Online:
				StatusString = modMain.msgStatusOnline;
				break;
			case UserStatus.DoNotDisturb:
				StatusString = modMain.msgStatusDoNotDisturb;
				break;
		}
		SendMessage(MessageType.Status, StatusString);
	}

	private enum MessageType
	{
		Connect,
		Chat,
		Status
	}

	private void SendMessage(MessageType Purpose,  // ERROR: Unsupported modifier : In, Optional
string Param)
	{
		StringBuilder Message = new StringBuilder(Param.Length + 8);

		switch (Purpose) {
			case MessageType.Connect:
				Message.Append(modMain.msgConnect);
				break;
			case MessageType.Chat:
				Message.Append(modMain.msgChat);
				break;
			case MessageType.Status:
				Message.Append(modMain.msgStatus);
				break;
		}

		Message.Append("|");
		Message.Append(Param);

		SendData(Message.ToString());
	}

	//====================================================================

	private void SendData(string Data)
	{
		if ((Connection != null))
		{
			Connection.SendData(Data);
		}
	}

	#endregion

	//====================================================================

	#region " Receiving data "

	private void mConnection_LineReceived(UserConnection Sender, string Data)
	{
		ProcessCommand(Data);
	}

	//====================================================================

	// Process the command received from the server, and take appropriate action.
	private void ProcessCommand(string strMessage)
	{

		// Message parts are divided by "|"  Break the string into an array accordingly.
		string[] dataArray = strMessage.Split('|');

		// dataArray(0) is the command.
		switch (dataArray[0]) {
			case modMain.msgChat:

				// Received a chat message, notify the container.
				if (ReceivedText != null) {
					ReceivedText(this, dataArray[1]);
				}

				break;
			case modMain.msgStatus:

				switch (dataArray[1]) {
					case modMain.msgStatusOnline:
						this.Status = UserStatus.Online;
						break;
					case modMain.msgStatusDoNotDisturb:
						this.Status = UserStatus.DoNotDisturb;
						break;
				}
				if (StatusChanged != null) {
					StatusChanged(this);
				}

				break;
		}

	}

	//====================================================================

	#endregion

	//====================================================================

	#region " Properties: Name, Address, Status "

	//====================================================================
	// Status
	//====================================================================

	private UserStatus mStatus = UserStatus.Offline;
	public UserStatus Status {
		get { return mStatus; }
		set { mStatus = value; }
	}

	public bool IsOnline()
	{
		bool functionReturnValue = false;
		return !(Status == UserStatus.Offline);
		return functionReturnValue;
	}

	//====================================================================
	// Name
	//====================================================================

	private string mName;
	public string Name {
		get { return mName; }
		set { mName = value; }
	}

	//====================================================================
	// Address
	//====================================================================

	private string mAddress;
	public string Address {
		get { return mAddress; }
		set { mAddress = value; }
	}

	//====================================================================
	#endregion

}
